package cmu;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.text.DecimalFormat;

public class Monitor {
	/**
	 * getTopData will return a BufferedReader which contains data of "top -b -n 1"
	 * @return BufferedReader 
	 * @throws Exception
	 */
	private BufferedReader getTopData() throws Exception{
		BufferedReader in = null;
		
		Runtime rt = Runtime.getRuntime(); 
		Process p = rt.exec("top -b -n 1");
		
		in = new BufferedReader(new InputStreamReader(p.getInputStream()));
		
		return in;
	}
	
	
	/**
	 * getCpuInfo will return the CPU utilization percentage
	 * @return double
	 * @throws Exception
	 */
	public double getCpuInfo() throws Exception{
		double cpuUsage = 0.0;
		BufferedReader in = null;	
		
		try{ 
			in = getTopData();
			String line = null;
			String[] array = null;
			int count = 0;
			
			while ((line = in.readLine()) != null){
				count++;
				
				// cpu utilization is on the 3rd row and 2nd col
				
				if (count < 3){
					// ignore first 2 rows
					continue;
				}else if (count == 3){
					array = line.split("\\s+");
					array = array[1].split("%");
					cpuUsage = Double.parseDouble(array[0]) ;
					break;
				}else{
					break;
				}
				
			}
			
		}catch (Exception e){
			System.out.println("Error in getCpuInfo: " + e.getMessage());
			e.printStackTrace();
		}finally{
			in.close();
		}
		
		return cpuUsage;
	}
	
	/**
	 * getMemInfo will return the Memory utilization percentage
	 * @return double
	 * @throws Exception
	 */
	public double getMemInfo() throws Exception{
		double memUsage = 0.0;
		
		BufferedReader in = null;	
		
		try{ 
			in = getTopData();
			String line = null;
			String[] array = null;
			int count = 0;
			
			while ((line = in.readLine()) != null){
				count++;
				// mem utilization is on the 4rd row 
				 
				if (count < 4){
					// ignore first 3 rows
					continue;
				}else if (count == 4){
					array = line.split("\\s+");
					String[] tmp;
					// extract size of memory
					tmp = array[1].split("k");
					Double total = Double.parseDouble(tmp[0]);
					// extract usage of memory
					tmp = array[3].split("k");
					Double usage = Double.parseDouble(tmp[0]);
					
					//get percentage usage
/*					int temp;
					// reserve 1 floating point
					temp = (int)((usage/total * 1000) + 0.5);
					memUsage = (((double)(temp))/1000) * 100;
*/
					memUsage = usage/total * 100;
					DecimalFormat df = new DecimalFormat("##.0");
					memUsage =Double.parseDouble(df.format(memUsage));
					break;
				}else{
					break;
				}
				
			}
			
		}catch (Exception e){
			System.out.println("Error in getMemInfo: " + e.getMessage());
			e.printStackTrace();
		}finally{
			in.close();
		}
		
		return memUsage;
	}
	
	/**
	 * getCpuWaitInfo will return the CPU waiting time percentage (waiting for I/O operation)
	 * @return double
	 * @throws Exception
	 */
	public double getCpuWaitInfo() throws Exception{
		double cpuWaitUsage = 0.0;
		BufferedReader in = null;	
		
		try{ 
			in = getTopData();
			String line = null;
			String[] array = null;
			int count = 0;
			
			while ((line = in.readLine()) != null){
				count++;
				
				// cpu utilization is on the 3rd row and 2nd col
				
				if (count < 3){
					// ignore first 2 rows
					continue;
				}else if (count == 3){
					array = line.split("\\s+");
					array = array[5].split("%");
					cpuWaitUsage = Double.parseDouble(array[0]) ;
					break;
				}else{
					break;
				}
				
			}
			
		}catch (Exception e){
			System.out.println("Error in getCpuWaitInfo: " + e.getMessage());
			e.printStackTrace();
		}finally{
			in.close();
		}
		
		return cpuWaitUsage;
	}

	/**
	 * getSwapInfo will return swap area utilization, if it changes dramatically, means we got physical mem bottle neck 
	 * @return double
	 * @throws Exception
	 */
	public double getSwapInfo() throws Exception{
		double swapUsage = 0.0;
		
		BufferedReader in = null;	
		
		try{ 
			in = getTopData();
			String line = null;
			String[] array = null;
			int count = 0;
			
			while ((line = in.readLine()) != null){
				count++;
				// swap utilization is on the 5rd row 
				//System.out.println(line);
				if (count < 5){
					// ignore first 4 rows
					continue;
				}else if (count == 5){
					array = line.split("\\s+");
					String[] tmp;
					// extract size of memory
					tmp = array[1].split("k");
					Double total = Double.parseDouble(tmp[0]);
					// extract usage of memory
					tmp = array[3].split("k");
					Double usage = Double.parseDouble(tmp[0]);
					
					//get percentage usage
/*					int temp;
					// reserve 1 floating point
					temp = (int)((usage/total * 1000) + 0.5);
					swapUsage = (((double)temp)/1000) * 100;
*/
					swapUsage = usage/total * 100;
					DecimalFormat df = new DecimalFormat("##.0");
					swapUsage = Double.parseDouble(df.format(swapUsage));
					
					break;
				}else{
					break;
				}
				
			}
			
		}catch (Exception e){
			System.out.println("Error in getSwapInfo: " + e.getMessage());
			e.printStackTrace();
		}finally{
			in.close();
		}
		
		return swapUsage;
	}

	/**
	 * getNetworkData will return result of command "sar -n DEV -u 1 1"
	 * @return BufferedReader
	 * @throws Exception
	 */
	private BufferedReader getNetworkData() throws Exception{
		BufferedReader in = null;
		
		Runtime rt = Runtime.getRuntime(); 
		Process p = rt.exec("sar -n DEV -u 1 1");
		
		in = new BufferedReader(new InputStreamReader(p.getInputStream()));
		
		return in;
	}
	
	/**
	 * getTxBytesInfo will return how many Kbytes transfered
	 * @return double
	 * @throws IOException 
	 */
	public double getTxBytesInfo() throws IOException{
		double bytes = 0.0;
		BufferedReader in = null;
		String line = null;
		String[] array = null;
		int count = 0;
		
		try{
			in = getNetworkData();
			
			while((line = in.readLine()) != null){
				count++;
				
				//System.out.println(line);
				
				if (count < 15 ){
					//skip the first 11 lines
					continue;
				}else if (count == 15){
					array = line.split("\\s+");
					bytes = Double.parseDouble(array[5]);
					break;
				}else{
					break;
				}
			}
		}catch (Exception e){
			System.out.println("Error in getTxBytesInfo: " + e.getMessage());
			e.printStackTrace();
		}finally{
			in.close();
		}
		
		
		return bytes;
	}
	
	/**
	 * getRxBytesInfo will return how many Kbytes received 
	 * @return double
	 * @throws IOException
	 */
	public double getRxBytesInfo() throws IOException{
		double bytes = 0.0;
		BufferedReader in = null;
		String line = null;
		String[] array = null;
		int count = 0;
		
		try{
			in = getNetworkData();
			
			while((line = in.readLine()) != null){
				count++;
				
				//System.out.println(line);
				
				if (count < 15 ){
					//skip the first 11 lines
					continue;
				}else if (count == 15){
					array = line.split("\\s+");
					bytes = Double.parseDouble(array[4]);
					break;
				}else{
					break;
				}
			}
		}catch (Exception e){
			System.out.println("Error in getRxBytesInfo: " + e.getMessage());
			e.printStackTrace();
		}finally{
			in.close();
		}
		
		
		return bytes;
	}

	/**
	 * getDiskData will return result of command "iostat -k" 
	 * @return BufferedReader
	 * @throws Exception
	 */
	private BufferedReader getDiskData() throws Exception{
		BufferedReader in = null;
		
		Runtime rt = Runtime.getRuntime(); 
		Process p = rt.exec("iostat -k");
		
		in = new BufferedReader(new InputStreamReader(p.getInputStream()));
		
		return in;
	}
	
	/**
	 * getRdDiskInfo will return how many kbytes read from disk
	 * @return double
	 * @throws IOException
	 */
	public double getRdDiskInfo() throws IOException{
		BufferedReader in = null;
		double bytes = 0.0;
		String line = null;
		String[] array = null;
		int count = 0;
		
		try{
			in = getDiskData();
			
			while((line = in.readLine()) != null){
				count++;
				
				//System.out.println(line);
				
				if (count < 7 ){
					//skip the first 2 lines
					continue;
				}else if (count == 7){
					array = line.split("\\s+");
					bytes = Double.parseDouble(array[2]);
					break;
				}else{
					break;
				}
			}
		}catch (Exception e){
			System.out.println("Error in getRdDiskInfo: " + e.getMessage());
			e.printStackTrace();
		}finally{
			in.close();
		}
		
		return bytes;
	}
	
	/**
	 * getWtDiskInfo will return how many kbytes write to the disk
	 * @return double
	 * @throws IOException
	 */
	public double getWtDiskInfo() throws IOException{
		BufferedReader in = null;
		double bytes = 0.0;
		String line = null;
		String[] array = null;
		int count = 0;
		
		try{
			in = getDiskData();
			
			while((line = in.readLine()) != null){
				count++;
				
				//System.out.println(line);
				
				if (count < 7 ){
					//skip the first 2 lines
					continue;
				}else if (count == 7){
					array = line.split("\\s+");
					bytes = Double.parseDouble(array[3]);
					break;
				}else{
					break;
				}
			}
		}catch (Exception e){
			System.out.println("Error in getWtDiskInfo: " + e.getMessage());
			e.printStackTrace();
		}finally{
			in.close();
		}
		
		return bytes;
	}
//class end
}